home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / emacssrc.zip / EMACSSRC.TAR / emacs-19.17 / src / vmstime.c < prev    next >
C/C++ Source or Header  |  1993-07-23  |  9KB  |  377 lines

  1. /* Time support for VMS.
  2.    Copyright (C) 1993 Free Software Foundation.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU Emacs is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "config.h"
  21. #include "vmstime.h"
  22.  
  23. long timezone=0;
  24. int daylight=0;
  25.  
  26. static char tzname_default[20]="";
  27. static char tzname_dst[20]="";
  28.  
  29. char *tzname[2] = { tzname_default, tzname_dst };
  30.  
  31. static long internal_daylight=0;
  32. static char daylight_set=0;
  33.  
  34. static long read_time(const char *nptr, const char **endptr,
  35.               int sign_allowed_p)
  36. {
  37.   int t;
  38.  
  39.   *endptr = nptr;
  40.  
  41.   /* This routine trusts the user very much, and does no checks!
  42.       The only exception is this: */
  43.   if (!sign_allowed_p && (*nptr == '-' || *nptr == '+'))
  44.     return 0;
  45.  
  46.   t = strtol(*endptr, endptr, 10) * 3600;
  47.   if (**endptr != ':' || **endptr == '+' || **endptr == '-')
  48.     return t;
  49.   (*endptr)++;
  50.  
  51.   t = t + strtol(*endptr, endptr, 10) * 60;
  52.   if (**endptr != ':' || **endptr == '+' || **endptr == '-')
  53.     return t;
  54.   (*endptr)++;
  55.  
  56.   return t + strtol(*endptr, endptr, 10);
  57. }
  58.  
  59. static void read_dst_time(const char *nptr, const char **endptr,
  60.               int *m, int *n, int *d,
  61.               int *leap_p)
  62. {
  63.   time_t bintim = time(0);
  64.   struct tm *lc = localtime(&bintim);
  65.  
  66.   *leap_p = 1;
  67.   *m = 0;            /* When m and n are 0, a Julian */
  68.   *n = 0;            /* date has been inserted in d */
  69.  
  70.   switch(*nptr)
  71.     {
  72.     case 'M':
  73.       {
  74.     /* This routine counts on the user to have specified "Mm.n.d",
  75.        where 1 <= n <= 5, 1 <= m <= 12, 0 <= d <= 6 */
  76.  
  77.     *m = strtol(++nptr, endptr, 10);
  78.     (*endptr)++;        /* Skip the dot */
  79.     *n = strtol(*endptr, endptr, 10);
  80.     (*endptr)++;        /* Skip the dot */
  81.     *d = strtol(*endptr, endptr, 10);
  82.  
  83.     return;
  84.       }
  85.     case 'J':
  86.       *leap_p = 0;        /* Never count with leap years */
  87.     default: /* trust the user to have inserted a number! */
  88.       *d = strtol(++nptr, endptr, 10);
  89.       return;
  90.     }
  91. }
  92.  
  93. struct vms_vectim
  94. {
  95.   short year, month, day, hour, minute, second, centi_second;
  96. };
  97. static void find_dst_time(int m, int n, long d,
  98.               int hour, int minute, int second,
  99.               int leap_p,
  100.               long vms_internal_time[2])
  101. {
  102.   long status = SYS$GETTIM(vms_internal_time);
  103.   struct vms_vectim vms_vectime;
  104.   status = SYS$NUMTIM(&vms_vectime, vms_internal_time);
  105.  
  106.   if (m == 0 && n == 0)
  107.     {
  108.       long tmp_vms_internal_time[2][2];
  109.       long day_of_year;
  110.       long tmp_operation = LIB$K_DAY_OF_YEAR;
  111.  
  112.       status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation, &day_of_year,
  113.                       vms_internal_time);
  114.       
  115.       vms_vectime.month = 2;
  116.       vms_vectime.day = 29;
  117.       status = LIB$CVT_VECTIM(&vms_vectime, tmp_vms_internal_time[0]);
  118.       if (status & 1) /* This is a leap year */
  119.     {
  120.       if (!leap_p && d > 59)
  121.         d ++;        /* If we don't count with 29th Feb,
  122.                    and this is a leap year, count up,
  123.                    to make day 60 really become the
  124.                    1st March. */
  125.     }
  126.       /* 1st January, at midnight */
  127.       vms_vectime.month = 1;
  128.       vms_vectime.day = 1;
  129.       vms_vectime.hour = hour;
  130.       vms_vectime.minute = minute;
  131.       vms_vectime.second = second;
  132.       vms_vectime.centi_second = 0;
  133.       status = LIB$CVT_VECTIM(&vms_vectime, tmp_vms_internal_time[0]);
  134.       tmp_operation = LIB$K_DELTA_DAYS;
  135.       status = LIB$CVT_TO_INTERNAL_TIME(&tmp_operation, &d,
  136.                     tmp_vms_internal_time[1]);
  137.       /* now, tmp_vms_interval_time[0] contains 1st Jan, 00:00:00,
  138.      and  tmp_vms_interval_time[1] contains delta time +d days.
  139.      Let's just add them together */
  140.       status = LIB$ADD_TIMES(tmp_vms_internal_time[0],
  141.                  tmp_vms_internal_time[1],
  142.                  vms_internal_time);
  143.     }
  144.   else
  145.     {
  146.       long tmp_vms_internal_time[2];
  147.       long day_of_week;
  148.       long tmp_operation = LIB$K_DAY_OF_YEAR;
  149.  
  150.       if (d == 0) /* 0 is Sunday, which isn't compatible with VMS,
  151.              where day_of_week is 1 -- 7, and 1 is Monday */
  152.     {
  153.       d = 7; /* So a simple conversion is required */
  154.     }
  155.       vms_vectime.month = m;
  156.       vms_vectime.day = 1;
  157.       vms_vectime.hour = hour;
  158.       vms_vectime.minute = minute;
  159.       vms_vectime.second = second;
  160.       vms_vectime.centi_second = 0;
  161.       status = LIB$CVT_VECTIM(&vms_vectime, tmp_vms_internal_time);
  162.       tmp_operation = LIB$K_DAY_OF_WEEK;
  163.       status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation, &day_of_week,
  164.                       tmp_vms_internal_time);
  165.       d -= day_of_week;
  166.       if (d < 0)
  167.     {
  168.       d += 7;
  169.     }
  170.       vms_vectime.day += (n-1)*7 + d;
  171.       status = LIB$CVT_VECTIM(&vms_vectime, vms_internal_time);
  172.       if (!(status & 1))
  173.     {
  174.       vms_vectime.day -= 7;    /* n was probably 5 */
  175.       status = LIB$CVT_VECTIM(&vms_vectime, vms_internal_time);
  176.     }
  177.     }
  178. }
  179.  
  180. static cmp_vms_internal_times(long vms_internal_time1[2],
  181.                   long vms_internal_time2[2])
  182. {
  183.   if (vms_internal_time1[1] < vms_internal_time2[1])
  184.     return -1;
  185.   else
  186.     if (vms_internal_time1[1] > vms_internal_time2[1])
  187.       return 1;
  188.  
  189.   if (vms_internal_time1[0] < vms_internal_time2[0])
  190.     return -1;
  191.   else
  192.     if (vms_internal_time1[0] > vms_internal_time2[0])
  193.       return 1;
  194.  
  195.   return 0;
  196. }
  197.  
  198. /* -------------------------- Global routines ------------------------------ */
  199.  
  200. #ifdef tzset
  201. #undef tzset
  202. #endif
  203. void sys_tzset()
  204. {
  205.   char *TZ;
  206.   char *p, *q;
  207.  
  208.   if (daylight_set)
  209.     return;
  210.  
  211.   daylight = 0;
  212.  
  213.   if ((TZ = getenv("TZ")) == 0)
  214.     return;
  215.  
  216.   p = TZ;
  217.   q = tzname[0];
  218.  
  219.   while(*p != '\0'
  220.     && (*p <'0' || *p > '9') && *p != '-' && *p != '+' && *p != ',')
  221.     *q++ = *p++;
  222.   *q = '\0';
  223.  
  224.   /* This is special for VMS, so I don't care if it doesn't exist anywhere
  225.      else */
  226.  
  227.   timezone = read_time(p, &p, 1);
  228.  
  229.   q = tzname[1];
  230.  
  231.   while(*p != '\0'
  232.     && (*p <'0' || *p > '9') && *p != '-' && *p != '+' && *p != ',')
  233.     *q++ = *p++;
  234.   *q = '\0';
  235.  
  236.   if (*p != '-' && *p != '+' && !(*p >='0' && *p <= '9'))
  237.     internal_daylight = timezone - 3600;
  238.   else
  239.     internal_daylight = read_time(p, &p, 1);
  240.  
  241.   if (*p == ',')
  242.     {
  243.       int start_m;
  244.       int start_n;
  245.       int start_d;
  246.       int start_leap_p;
  247.       int start_hour=2, start_minute=0, start_second=0;
  248.  
  249.       p++;
  250.       read_dst_time(p, &p, &start_m, &start_n, &start_d, &start_leap_p);
  251.       if (*p == '/')
  252.     {
  253.       long tmp = read_time (++p, &p, 0);
  254.       start_hour = tmp / 3600;
  255.       start_minute = (tmp % 3600) / 60;
  256.       start_second = tmp % 60;
  257.     }
  258.       if (*p == ',')
  259.     {
  260.       int end_m;
  261.       int end_n;
  262.       int end_d;
  263.       int end_leap_p;
  264.       int end_hour=2, end_minute=0, end_second=0;
  265.  
  266.       p++;
  267.       read_dst_time(p, &p, &end_m, &end_n, &end_d, &end_leap_p);
  268.       if (*p == '/')
  269.         {
  270.           long tmp = read_time (++p, &p, 0);
  271.           end_hour = tmp / 3600;
  272.           end_minute = (tmp % 3600) / 60;
  273.           end_second = tmp % 60;
  274.         }
  275.       {
  276.         long vms_internal_time[3][2];
  277.         find_dst_time(start_m, start_n, start_d,
  278.               start_hour, start_minute, start_second,
  279.               start_leap_p,
  280.               vms_internal_time[0]);
  281.         SYS$GETTIM(&vms_internal_time[1]);
  282.         find_dst_time(end_m, end_n, end_d,
  283.               end_hour, end_minute, end_second,
  284.               end_leap_p,
  285.               vms_internal_time[2]);
  286.         if (cmp_vms_internal_times(vms_internal_time[0],
  287.                       vms_internal_time[1]) < 0
  288.         && cmp_vms_internal_times(vms_internal_time[1],
  289.                      vms_internal_time[2]) < 0)
  290.           daylight = 1;
  291.       }
  292.     }
  293.     }
  294. }  
  295.  
  296. #ifdef localtime
  297. #undef localtime
  298. #endif
  299. struct tm *sys_localtime(time_t *clock)
  300. {
  301.   struct tm *tmp = localtime(clock);
  302.  
  303.   sys_tzset();
  304.   tmp->tm_isdst = daylight;
  305.  
  306.   return tmp;
  307. }
  308.  
  309. #ifdef gmtime
  310. #undef gmtime
  311. #endif
  312. struct tm *sys_gmtime(time_t *clock)
  313. {
  314.   static struct tm gmt;
  315.   struct vms_vectim tmp_vectime;
  316.   long vms_internal_time[3][2];
  317.   long tmp_operation = LIB$K_DELTA_SECONDS;
  318.   long status;
  319.   long tmp_offset;
  320.   char tmp_o_sign;
  321.  
  322.   sys_tzset();
  323.   
  324.   if (daylight)
  325.     tmp_offset = internal_daylight;
  326.   else
  327.     tmp_offset = timezone;
  328.  
  329.   if (tmp_offset < 0)
  330.     {
  331.       tmp_o_sign = -1;
  332.       tmp_offset = -tmp_offset;
  333.     }
  334.   else
  335.     tmp_o_sign = 1;
  336.  
  337.   status = LIB$CVT_TO_INTERNAL_TIME(&tmp_operation, &tmp_offset,
  338.                     vms_internal_time[1]);
  339.   status = SYS$GETTIM(vms_internal_time[0]);
  340.   if (tmp_o_sign < 0)
  341.     {
  342.       status = LIB$SUB_TIMES(vms_internal_time[0],
  343.                  vms_internal_time[1],
  344.                  vms_internal_time[2]);
  345.     }
  346.   else
  347.     {
  348.       status = LIB$ADD_TIMES(vms_internal_time[0],
  349.                  vms_internal_time[1],
  350.                  vms_internal_time[2]);
  351.     }
  352.  
  353.   status = SYS$NUMTIM(&tmp_vectime, vms_internal_time[2]);
  354.   gmt.tm_sec = tmp_vectime.second;
  355.   gmt.tm_min = tmp_vectime.minute;
  356.   gmt.tm_hour = tmp_vectime.hour;
  357.   gmt.tm_mday = tmp_vectime.day;
  358.   gmt.tm_mon = tmp_vectime.month - 1;
  359.   gmt.tm_year = tmp_vectime.year % 100;
  360.  
  361.   tmp_operation = LIB$K_DAY_OF_WEEK;
  362.   status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation,
  363.                       &gmt.tm_wday,
  364.                       vms_internal_time[2]);
  365.   if (gmt.tm_wday == 7) gmt.tm_wday = 0;
  366.  
  367.   tmp_operation = LIB$K_DAY_OF_YEAR;
  368.   status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation,
  369.                       &gmt.tm_yday,
  370.                       vms_internal_time[2]);
  371.   gmt.tm_yday--;
  372.   gmt.tm_isdst = daylight;
  373.  
  374.   return &gmt;
  375. }
  376.  
  377.